//============================================================================
// Name        : ThreadingPatternGenomAnalyser.cpp
// Author      : Anthea Neums, Jonas Halbach
//			   :
// Description : This Class Starts a defined number of Threads to solve the pattern genom matchng problem.
//============================================================================

#include "ThreadingPatternGenomAnalyser.h"

using namespace std;

namespace algorithm
{


	ThreadingPatternGenomAnalyser::ThreadingPatternGenomAnalyser(char *patternSource, char *genomSource, int wordlength, int threadCount) : wordlength(wordlength), threadCount(threadCount) {

		genomReader = new FileReader(genomSource);
		patternReader = new FileReader(patternSource);
		founds = new list<Found *>();
		
	}

	ThreadingPatternGenomAnalyser::~ThreadingPatternGenomAnalyser(){
		vector<PatternGenomAnalyserThreadStarter *>::iterator threadStarterIterator = threadStarterVector.begin();
		while(threadStarterIterator != threadStarterVector.end())
		{
			delete (*threadStarterIterator);
			threadStarterIterator++;
		}
		threadStarterVector.clear();
	
		list<thread *>::iterator threadListIterator = threadList.begin();
		while(threadListIterator != threadList.end())
		{
			delete (*threadListIterator);
			threadListIterator++;
		}
		threadList.clear();
	}
	/**
	* This Method prints the Vector of the founded matches and adds "Ergebnisliste"
	* at the front and "Ende Ergebnisse" after printing the information about the
	* founds.
	*/
	void ThreadingPatternGenomAnalyser::printFounds() {
		cout << "Ergebnisliste:" << endl;
		printMatches();
		cout << "Ende Ergebnisse" << endl;
	}

	/**
	* This Method prints the Vector of the founded matches and adds a
	* linenumber to each found.
	*/
	void ThreadingPatternGenomAnalyser::printMatches() {
		if(founds != NULL)
		{
			List::iterator it = founds->begin();
			int i = 0;

			while (it != founds->end()) {

				cout << "\t" << i << ") " << flush;
				(*it)->print();
				it++;
				i++;
			}
		}
	}

	
	/*
	* Getting a list of founds which stores the founded matches.
	*/
	list<Found *> *ThreadingPatternGenomAnalyser::getFounds() {
		return founds;
	}

	/**
	* This Method starts some threads to match the pattern and the genom.
	*/
	void ThreadingPatternGenomAnalyser::findSimilarStrings()
	{
		threadStarterVector = vector<PatternGenomAnalyserThreadStarter *>();
		threadList = list<thread *>();
		int genomPartLength = genomReader->getSize() / threadCount;

		int rest = genomReader->getSize() % threadCount;
		int startpos = 0;
		genomPartLength += rest;
		for(int threadNumber = 0; threadNumber < threadCount; threadNumber++)
		{ 
			if(threadNumber == 0)
			{
				startpos = 0;
				genomPartLength += rest;
			}
			else
			{
				startpos = threadNumber * genomPartLength + rest;
				genomPartLength = genomReader->getSize() / threadCount;
			}
			

			PatternGenomAnalyserThreadStarter *threadStarter = new PatternGenomAnalyserThreadStarter(patternReader, genomReader, wordlength, startpos, genomPartLength, threadNumber);
			threadStarterVector.push_back(threadStarter);
			thread *actThread = new thread(ref(*threadStarter));
			threadList.push_back(actThread);


		}

		list<thread *>::iterator threadIterator = threadList.begin();
		while(threadIterator != threadList.end())
		{
			(*threadIterator)->join();
			threadIterator++;
		}
	
		
		//Storing actual found list
		//iterate over the threadStarter Vector
		//Getting the found list of the actural threadStarterElement
		//Prooving if null
		//If complete list size == 0 -> complete list.insert(founds, end)
		//else 
		//	while(completeList.last.contains(actualfoundList.first) && actualfoundList != end())
		// {
		//		actualfountlist.pop_first();	
		// }
		// if(acttualfoundlist.size() > 0) -> completeList.insert(actualfoundList,end);
		vector<PatternGenomAnalyserThreadStarter *>::iterator threadStarterIterator = threadStarterVector.begin();
		while(threadStarterIterator != threadStarterVector.end())
		{
			list<algorithm::Found *> *nextFounds = (*threadStarterIterator)->getPatternGenomAnalyser()->getFounds();
			if(nextFounds->size() > 0)
			{
				if(founds->size() == 0)
				{
					founds->insert(founds->end(), nextFounds->begin(), nextFounds->end());
				}
				else
				{
					while(founds->back()->contains(nextFounds->front()) && nextFounds->size() > 0)
					{
						nextFounds->pop_front();
					}
					if(nextFounds->size() > 0)
					{
						founds->insert(founds->end(), nextFounds->begin(), nextFounds->end());
					}
				}
			}
			threadStarterIterator++;
		}


	}

}